﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using ALDIOrganizer;
using ALDIOrganizer.Properties;


namespace Generator
{   
    public partial class Engine
    {
        #region auxiliary methods (deep copying 1 & 2 dimensional arrays / enlarging fixed arrays)
        // a deep-Copy of one-dimensional array
        public static T[] ArrayDeepCopy<T>(T[] original) where T : struct
        {
            var copy = new T[original.Length];

            original.CopyTo(copy, 0);

            return copy;            
        }

        /* a deep Copy of two-dimensional array
         * 
         * we use it for Solution shift_emp property, which is bool[,] */
        public static T[,] SquareArrayDeepCopy<T>(T[,] original)
        {
            var copy = new T[
                original.GetUpperBound(0)+1,
                original.GetUpperBound(1)+1];
            Array.Copy(
                original,
                copy,
                original.Length);
            return copy;
        }

        /* written solely for adding new elements to engShift.myOverlaps -
         * * an array of integer which holds the GetEmployeeIDs of other Shifts
         * * that the Shift in question overlaps with.
         * * 
         * * primarily, myOverlaps was a List<int> (which IsAllowed for "building it up"
         * * simply by calling Add -
         * * but since performance is very important, I don't want any List<int>pShift in this structure.
         * * int[] is just fine (since the list of overlaps is created once and does not change).
         * * Keep it as simple as possible. */
        private static int[] ExtendIntArray(int[] pIntArray, int pNewElement)
        {
            var result = new int[pIntArray.Length + 1];
            pIntArray.CopyTo(result, 0);
            result[pIntArray.Length] = pNewElement;
            return result;
        }

        #endregion
                
        public Solution solution;
        public Solution solutionFinal;
        private readonly Parameters parameters;
        public Dictionary<Candidate, EmployeeInRota> dicCandidatesStaff;

        private Template _template; // the Template (or do we only have to remember the working hours?)
        private Rota _rota;

        public Engine()
        {
            parameters = new Parameters();
        }

        public Engine(Parameters pParameters) : this()
        {
            parameters = pParameters;
            Penalties.SetParameters(pParameters);
            /* we don't have to worry whether they've been generated already
             * because the Penalties class itself checks for that and ignores the call
             * if the job has already been done */         
        }
                

        /* once we have found the solution we were looking for,
         * we now need to "translate it back" into an instance of a RotaPackaging class
         * so that we can present the result for the user */
        public void FillRotaWithFinalSolution(Solution pSolution)
        {
            Report report;
            pSolution.ComputePenalty(
                true,
                out report); 
                
            // now we can start adding Shifts!                        
            foreach (var es in pSolution.Shifts)
            {
                var s = new ALDIOrganizer.Shift
                            {
                                opening = es.FromTo.Opening,
                                closing = es.FromTo.Closing,
                                Start = es.FromTo.Start,
                                Finish = es.FromTo.End,
                                Day = (Weekday)es.Day
                            };

                // it could technically be put in one line, but I'm breaking it down for clarity here
                Candidate ec = pSolution.Candidates[es.Chosen];                                
                EmployeeInRota e = dicCandidatesStaff[ec];
                Int64 eID = e.Employee.ID;                                
                var ls = new ShiftTandem {s};

                _rota.AddShifts(ls, s.Day, new RowTag(eID), false);                
                report.AddAlias(ec.ID, eID);                
            }
            foreach (var candidate in pSolution.Candidates)
            {
                var emp = dicCandidatesStaff[candidate];
                var id = emp.Employee.ID;
                report.AddOvertime(
                    id,
                    candidate.Hours / 4F,
                    candidate.ContractHrs);
            }
            _rota.FinalReport = report;
        }

        
    }

    
}
